﻿using System;
using System.Runtime.InteropServices;

namespace Awesom_O_Controller
{
    public class SendMessenger
    {
        #region WM_MESSAGES

        protected class WMmessages
        {
            public const int WmNull = 0x000;
            public const int WmCreate = 0x001;
            public const int WmDestroy = 0x002;
            public const int WmMove = 0x003;
            public const int WmSize = 0x005;
            public const int WmActivate = 0x006;
            public const int WmSetfocus = 0x007;
            public const int WmKillfocus = 0x008;
            public const int WmEnable = 0x00A;
            public const int WmSetredraw = 0x00B;
            public const int WmSettext = 0x00C;
            public const int WmGettext = 0x00D;
            public const int WmGettextlength = 0x00E;
            public const int WmPaint = 0x00F;
            public const int WmClose = 0x010;
            public const int WmQueryendsession = 0x011;
            public const int WmQuit = 0x012;
            public const int WmQueryopen = 0x013;
            public const int WmErasebkgnd = 0x014;
            public const int WmSyscolorchange = 0x015;
            public const int WmEndsession = 0x016;
            public const int WmShowwindow = 0x018;
            public const int WmWininichange = 0x01A;
            public const int WmDevmodechange = 0x01B;
            public const int WmActivateapp = 0x01C;
            public const int WmFontchange = 0x01D;
            public const int WmTimechange = 0x01E;
            public const int WmCancelmode = 0x01F;
            public const int WmSetcursor = 0x020;
            public const int WmMouseactivate = 0x021;
            public const int WmChildactivate = 0x022;
            public const int WmQueuesync = 0x023;
            public const int WmGetminmaxinfo = 0x024;
            public const int WmPainticon = 0x026;
            public const int WmIconerasebkgnd = 0x027;
            public const int WmNextdlgctl = 0x028;
            public const int WmSpoolerstatus = 0x02A;
            public const int WmDrawitem = 0x02B;
            public const int WmMeasureitem = 0x02C;
            public const int WmDeleteitem = 0x02D;
            public const int WmVkeytoitem = 0x02E;
            public const int WmChartoitem = 0x02F;
            public const int WmSetfont = 0x030;
            public const int WmGetfont = 0x031;
            public const int WmSethotkey = 0x032;
            public const int WmGethotkey = 0x033;
            public const int WmQuerydragicon = 0x037;
            public const int WmCompareitem = 0x039;
            public const int WmCompacting = 0x041;
            public const int WmCommnotify = 0x044; /* no longer suported */
            public const int WmWindowposchanging = 0x046;
            public const int WmWindowposchanged = 0x047;
            public const int WmPower = 0x048;
            public const int WmCopydata = 0x04A;
            public const int WmCanceljournal = 0x04B;
            public const int WmUser = 0x400;
            public const int WmNotify = 0x04E;
            public const int WmInputlangchangerequest = 0x050;
            public const int WmInputlangchange = 0x051;
            public const int WmTcard = 0x052;
            public const int WmHelp = 0x053;
            public const int WmUserchanged = 0x054;
            public const int WmNotifyformat = 0x055;
            public const int WmContextmenu = 0x07B;
            public const int WmStylechanging = 0x07C;
            public const int WmStylechanged = 0x07D;
            public const int WmDisplaychange = 0x07E;
            public const int WmGeticon = 0x07F;
            public const int WmSeticon = 0x080;
            public const int WmNccreate = 0x081;
            public const int WmNcdestroy = 0x082;
            public const int WmNccalcsize = 0x083;
            public const int WmNchittest = 0x084;
            public const int WmNcpaint = 0x085;
            public const int WmNcactivate = 0x086;
            public const int WmGetdlgcode = 0x087;
            public const int WmSyncpaint = 0x088;
            public const int WmNcmousemove = 0x0A0;
            public const int WmNclbuttondown = 0x0A1;
            public const int WmNclbuttonup = 0x0A2;
            public const int WmNclbuttondblclk = 0x0A3;
            public const int WmNcrbuttondown = 0x0A4;
            public const int WmNcrbuttonup = 0x0A5;
            public const int WmNcrbuttondblclk = 0x0A6;
            public const int WmNcmbuttondown = 0x0A7;
            public const int WmNcmbuttonup = 0x0A8;
            public const int WmNcmbuttondblclk = 0x0A9;
            public const int WmNcxbuttondown = 0x0AB;
            public const int WmNcxbuttonup = 0x0AC;
            public const int WmNcxbuttondblclk = 0x0AD;
            public const int WmInput = 0x0FF;
            public const int WmKeyfirst = 0x100;
            public const int WmKeydown = 0x100;
            public const int WmKeyup = 0x101;
            public const int WmChar = 0x102;
            public const int WmDeadchar = 0x103;
            public const int WmSyskeydown = 0x104;
            public const int WmSyskeyup = 0x105;
            public const int WmSyschar = 0x106;
            public const int WmSysdeadchar = 0x107;
            public const int WmUnichar = 0x109;
            public const int WmKeylast = 0x109;
            public const int WmImeStartcomposition = 0x10D;
            public const int WmImeEndcomposition = 0x10E;
            public const int WmImeComposition = 0x10F;
            public const int WmImeKeylast = 0x10F;
            public const int WmInitdialog = 0x110;
            public const int WmCommand = 0x111;
            public const int WmSyscommand = 0x112;
            public const int WmTimer = 0x113;
            public const int WmHscroll = 0x114;
            public const int WmVscroll = 0x115;
            public const int WmInitmenu = 0x116;
            public const int WmInitmenupopup = 0x117;
            public const int WmMenuselect = 0x11F;
            public const int WmMenuchar = 0x120;
            public const int WmEnteridle = 0x121;
            public const int WmMenurbuttonup = 0x122;
            public const int WmMenudrag = 0x123;
            public const int WmMenugetobject = 0x124;
            public const int WmUninitmenupopup = 0x125;
            public const int WmMenucommand = 0x126;
            public const int WmChangeuistate = 0x127;
            public const int WmUpdateuistate = 0x128;
            public const int WmQueryuistate = 0x129;
            public const int WmCtlcolormsgbox = 0x132;
            public const int WmCtlcoloredit = 0x133;
            public const int WmCtlcolorlistbox = 0x134;
            public const int WmCtlcolorbtn = 0x135;
            public const int WmCtlcolordlg = 0x136;
            public const int WmCtlcolorscrollbar = 0x137;
            public const int WmCtlcolorstatic = 0x138;
            public const int MnGethmenu = 0x1E1;
            public const int WmMousefirst = 0x200;
            public const int WmMousemove = 0x200;
            public const int WmLbuttondown = 0x201;
            public const int WmLbuttonup = 0x202;
            public const int WmLbuttondblclk = 0x203;
            public const int WmRbuttondown = 0x204;
            public const int WmRbuttonup = 0x205;
            public const int WmRbuttondblclk = 0x206;
            public const int WmMbuttondown = 0x207;
            public const int WmMbuttonup = 0x208;
            public const int WmMbuttondblclk = 0x209;
            public const int WmMousewheel = 0x20A;
            public const int WmXbuttondown = 0x20B;
            public const int WmXbuttonup = 0x20C;
            public const int WmXbuttondblclk = 0x20D;
            public const int WmMouselast = 0x20A;
            public const int WmParentnotify = 0x210;
            public const int WmEntermenuloop = 0x211;
            public const int WmExitmenuloop = 0x212;
            public const int WmNextmenu = 0x213;
            public const int WmSizing = 0x214;
            public const int WmCapturechanged = 0x215;
            public const int WmMoving = 0x216;
            public const int WmPowerbroadcast = 0x218;
            public const int WmDevicechange = 0x219;
            public const int WmMdicreate = 0x220;
            public const int WmMdidestroy = 0x221;
            public const int WmMdiactivate = 0x222;
            public const int WmMdirestore = 0x223;
            public const int WmMdinext = 0x224;
            public const int WmMdimaximize = 0x225;
            public const int WmMditile = 0x226;
            public const int WmMdicascade = 0x227;
            public const int WmMdiiconarrange = 0x228;
            public const int WmMdigetactive = 0x229;
            public const int WmMdisetmenu = 0x230;
            public const int WmEntersizemove = 0x231;
            public const int WmExitsizemove = 0x232;
            public const int WmDropfiles = 0x233;
            public const int WmMdirefreshmenu = 0x234;
            public const int WmImeSetcontext = 0x281;
            public const int WmImeNotify = 0x282;
            public const int WmImeControl = 0x283;
            public const int WmImeCompositionfull = 0x284;
            public const int WmImeSelect = 0x285;
            public const int WmImeChar = 0x286;
            public const int WmImeRequest = 0x288;
            public const int WmImeKeydown = 0x290;
            public const int WmImeKeyup = 0x291;
            public const int WmMousehover = 0x2A1;
            public const int WmMouseleave = 0x2A3;
            public const int WmNcmousehover = 0x2A0;
            public const int WmNcmouseleave = 0x2A2;
            public const int WmWtssessionChange = 0x2B1;
            public const int WmTabletFirst = 0x2c0;
            public const int WmTabletLast = 0x2df;
            public const int WmCut = 0x300;
            public const int WmCopy = 0x301;
            public const int WmPaste = 0x302;
            public const int WmClear = 0x303;
            public const int WmUndo = 0x304;
            public const int WmRenderformat = 0x305;
            public const int WmRenderallformats = 0x306;
            public const int WmDestroyclipboard = 0x307;
            public const int WmDrawclipboard = 0x308;
            public const int WmPaintclipboard = 0x309;
            public const int WmVscrollclipboard = 0x30A;
            public const int WmSizeclipboard = 0x30B;
            public const int WmAskcbformatname = 0x30C;
            public const int WmChangecbchain = 0x30D;
            public const int WmHscrollclipboard = 0x30E;
            public const int WmQuerynewpalette = 0x30F;
            public const int WmPaletteischanging = 0x310;
            public const int WmPalettechanged = 0x311;
            public const int WmHotkey = 0x312;
            public const int WmPrint = 0x317;
            public const int WmPrintclient = 0x318;
            public const int WmAppcommand = 0x319;
            public const int WmThemechanged = 0x31A;
            public const int WmHandheldfirst = 0x358;
            public const int WmHandheldlast = 0x35F;
            public const int WmAfxfirst = 0x360;
            public const int WmAfxlast = 0x37F;
            public const int WmPenwinfirst = 0x380;
            public const int WmPenwinlast = 0x38F;
        }

        #endregion

        #region MK_Controls
        /*
        * Key State Masks for Mouse Messages
        */
        protected class MkControls
        {
            public const int MkLbutton = 0x0001;
            public const int MkRbutton = 0x0002;
            public const int MkShift = 0x0004;
            public const int MkControl = 0x0008;
            public const int MkMbutton = 0x0010;
        }

        #endregion

        #region Virtual Keys

        protected enum Vk
        {
            VkLbutton = 0x01,   //Left mouse button
            VkRbutton = 0x02,   //Right mouse button
            VkCancel = 0x03,   //Control-break processing
            VkMbutton = 0x04, //Middle mouse button (three-button mouse)
            VkBack = 0x08,   //BACKSPACE key
            VkTab = 0x09,   //TAB key
            VkClear = 0x0C,     //CLEAR key
            VkReturn = 0x0D,   //ENTER key
            VkShift = 0x10,   //SHIFT key
            VkControl = 0x11,  //CTRL key
            VkMenu = 0x12,    //ALT key
            VkPause = 0x13,  //PAUSE key
            VkCapital = 0x14,   //CAPS LOCK key
            VkEscape = 0x1B,   //ESC key
            VkSpace = 0x20,   //SPACEBAR
            VkPrior = 0x21,   //PAGE UP key
            VkNext = 0x22,   //PAGE DOWN key
            VkEnd = 0x23,   //END key
            VkHome = 0x24,   //HOME key
            VkLeft = 0x25,  //LEFT ARROW key
            VkUp = 0x26,   //UP ARROW key
            VkRight = 0x27,   //RIGHT ARROW key
            VkDown = 0x28,   //DOWN ARROW key
            VkSelect = 0x29,   //SELECT key
            VkPrint = 0x2A,   //PRINT key
            VkExecute = 0x2B,   //EXECUTE key
            VkSnapshot = 0x2C,   //PRINT SCREEN key
            VkInsert = 0x2D,   //INS key
            VkDelete = 0x2E,   //DEL key
            VkHelp = 0x2F,   //HELP key
            Vk0 = 0x30,   //0 key
            Vk1 = 0x31,   //1 key
            Vk2 = 0x32,   //2 key
            Vk3 = 0x33,   //3 key
            Vk4 = 0x34,   //4 key
            Vk5 = 0x35,   //5 key
            Vk6 = 0x36,   //6 key
            Vk7 = 0x37,   //7 key
            Vk8 = 0x38,   //8 key
            Vk9 = 0x39,   //9 key
            VkA = 0x41,   //A key
            VkB = 0x42,   //B key
            VkC = 0x43,   //C key
            VkD = 0x44,   //D key
            VkE = 0x45,   //E key
            VkF = 0x46,   //F key
            VkG = 0x47,   //G key
            VkH = 0x48,   //H key
            VkI = 0x49,   //I key
            VkJ = 0x4A,   //J key
            VkK = 0x4B,   //K key
            VkL = 0x4C,   //L key
            VkM = 0x4D,   //M key
            VkN = 0x4E,   //N key
            VkO = 0x4F,   //O key
            VkP = 0x50,   //P key
            VkQ = 0x51,   //Q key
            VkR = 0x52,   //R key
            VkS = 0x53,   //S key
            VkT = 0x54,   //T key
            VkU = 0x55,   //U key
            VkV = 0x56,   //V key
            VkW = 0x57,   //W key
            VkX = 0x58,   //X key
            VkY = 0x59,   //Y key
            VkZ = 0x5A,   //Z key
            VkNumpad0 = 0x60,   //Numeric keypad 0 key
            VkNumpad1 = 0x61,   //Numeric keypad 1 key
            VkNumpad2 = 0x62,   //Numeric keypad 2 key
            VkNumpad3 = 0x63,   //Numeric keypad 3 key
            VkNumpad4 = 0x64,   //Numeric keypad 4 key
            VkNumpad5 = 0x65,   //Numeric keypad 5 key
            VkNumpad6 = 0x66,   //Numeric keypad 6 key
            VkNumpad7 = 0x67,   //Numeric keypad 7 key
            VkNumpad8 = 0x68,   //Numeric keypad 8 key
            VkNumpad9 = 0x69,   //Numeric keypad 9 key
            VkSeparator = 0x6C,   //Separator key
            VkSubtract = 0x6D,   //Subtract key
            VkDecimal = 0x6E,   //Decimal key
            VkDivide = 0x6F,   //Divide key
            VkF1 = 0x70,   //F1 key
            VkF2 = 0x71,   //F2 key
            VkF3 = 0x72,   //F3 key
            VkF4 = 0x73,   //F4 key
            VkF5 = 0x74,   //F5 key
            VkF6 = 0x75,   //F6 key
            VkF7 = 0x76,   //F7 key
            VkF8 = 0x77,   //F8 key
            VkF9 = 0x78,   //F9 key
            VkF10 = 0x79,  //F10 key
            VkF11 = 0x7A,  //F11 key
            VkF12 = 0x7B,  //F12 key
            VkScroll = 0x91,   //SCROLL LOCK key
            VkLshift = 0xA0,   //Left SHIFT key
            VkRshift = 0xA1,   //Right SHIFT key
            VkLcontrol = 0xA2, //Left CONTROL key
            VkRcontrol = 0xA3, //Right CONTROL key
            VkLmenu = 0xA4,    //Left MENU key
            VkRmenu = 0xA5,    //Right MENU key
            VkPlay = 0xFA,    //Play key
            VkZoom = 0xFB,   //Zoom key
        }

        #endregion

        #region ShowWindow Params

        protected class Sw
        {
            public const int SwHide = 0;
            public const int SwShownormal = 1;
            public const int SwShowminimized = 2;
            public const int SwShowmaximized = 3;
            public const int SwShownoactivate = 4;
            public const int SwShow = 5;
            public const int SwMinimize = 6;
            public const int SwShowminnoactive = 7;
            public const int SwShowna = 8;
            public const int SwRestore = 9;
            public const int SwShowdefault = 10;
            public const int SwForceminimize = 11;
        }

        #endregion

        #region Invokes

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 msg, IntPtr wParam, ref CopyDataSruct lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 msg, IntPtr wParam, String lParam);
        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        private struct CopyDataSruct
        {
// ReSharper disable UnaccessedField.Local
            public IntPtr DwData;
// ReSharper restore UnaccessedField.Local
// ReSharper disable UnaccessedField.Local
            public int CbData;
// ReSharper restore UnaccessedField.Local
            [MarshalAs(UnmanagedType.LPStr)]
// ReSharper disable UnaccessedField.Local
            public string LpData;
// ReSharper restore UnaccessedField.Local
        }

        #endregion

        protected IntPtr HWnd;

        protected SendMessenger(IntPtr windowhandle)
        {
            HWnd = windowhandle;
        }

        protected bool BringAppToFront()
        {
            return ShowWindow(HWnd, Sw.SwRestore);
        }

        protected IntPtr SendWmText(string msg)
        {
            return HWnd != IntPtr.Zero ? SendMessage(HWnd, WMmessages.WmSettext, IntPtr.Zero, msg) : IntPtr.Zero;
        }

        protected IntPtr MouseMove(int x, int y)
        {
            return HWnd != IntPtr.Zero ? SendMessage(HWnd, WMmessages.WmMousemove, IntPtr.Zero, MakeLParam(x, y)) : IntPtr.Zero;
        }

        protected IntPtr SendText(string msg, int delay)
        {
            IntPtr result = IntPtr.Zero;
            if (HWnd != IntPtr.Zero)
            {
                foreach (char t in msg)
                {
                    result = SendMessage(HWnd, WMmessages.WmChar, (IntPtr)t, IntPtr.Zero);
                    System.Threading.Thread.Sleep(delay);
                }
            }
            return result;
        }

        protected IntPtr SendKey(Vk vkey, int delay)
        {
            IntPtr result = IntPtr.Zero;
            if (HWnd != IntPtr.Zero)
            {
                SendMessage(HWnd, WMmessages.WmKeydown, (IntPtr)vkey, IntPtr.Zero);
                System.Threading.Thread.Sleep(delay);
                result = SendMessage(HWnd, WMmessages.WmKeyup, (IntPtr)vkey, IntPtr.Zero);
                System.Threading.Thread.Sleep(delay);
            }
            return result;
        }

        protected IntPtr SendLeftMouseClick(int x, int y, int delay)
        {
            IntPtr result = IntPtr.Zero;
            if (HWnd != IntPtr.Zero)
            {
                MouseMove(x, y);
                System.Threading.Thread.Sleep(delay);
                SendMessage(HWnd, WMmessages.WmLbuttondown, (IntPtr)MkControls.MkLbutton, MakeLParam(x, y));
                System.Threading.Thread.Sleep(delay);
                result = SendMessage(HWnd, WMmessages.WmLbuttonup, (IntPtr)MkControls.MkLbutton, MakeLParam(x, y));
                System.Threading.Thread.Sleep(delay);
            }
            return result;
        }

        protected IntPtr SendCopyDataMessage(int wParam, string msg)
        {
            if (HWnd != IntPtr.Zero)
            {
                byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);
                int len = sarr.Length;
                CopyDataSruct cds;
                cds.DwData = (IntPtr)wParam;
                cds.LpData = msg;
                cds.CbData = len + 1;
                return SendMessage(HWnd, WMmessages.WmCopydata, (IntPtr)wParam, ref cds);
            }
            return IntPtr.Zero;
        }

        private static IntPtr MakeLParam(int loWord, int hiWord)
        {
            return (IntPtr)((hiWord << 16) | (loWord & 0xffff));
        }
    }
}
